/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "ssi_environment.h"
#include "ssi_internals.h"
#include <io.h>
#include <direct.h>

//static int MAX_STACK_SIZE = 1000000;
static int MAX_STACK_SIZE = 14000000;

#define LOCAL_ONLY

CEnvironment::CEnvironment(void)
: ErrCount(0)
, WarnCount(0)
, StackAddr(0)
{
  int i;
  StackAddr = (unsigned int)&i;
}

CEnvironment::~CEnvironment(void)
{
}

CStatus CEnvironment::SetCWD(String& NewDir)
{
#ifdef LOCAL_ONLY
	if(chdir(NewDir.Str()) == 0){
		return STAT_OK;
	}else{
		MAKEERR1(ERR03501, NewDir.Str())
	}
#endif

  if(NewDir.GetLength() <= 0) return STAT_OK;
  //String Temp;
  //CStatus Ret = GetAbsolutePath(NewDir, Temp);
  //return STAT_OK;
  String Temp;
  String Drive;
  CStatus Ret = GetAbsolutePath(NewDir, Temp);
  if(!Ret) return Ret;

  //printf("New Dir: %s\n", Temp.Str());

  // To allow for only root drive... what a kludge...
  GetDrive(Temp, Drive);
  Drive = Drive + "\\";
  if(Drive == Temp){
    CWD = Temp;
    return STAT_OK;
  }

  struct _finddata_t c_file;
  long hFile;
  if( (hFile = _findfirst( Temp.Str(), &c_file )) == -1L ){
    _findclose(hFile);
    MAKEERR1(ERR03501, Temp.Str())
  }
  _findclose(hFile);
  CWD = Temp;
  return STAT_OK;  // It is a fully qualified path passed to the function

  //Ret = c_file.name;

  //char fpath[MAX_SSI_CHARS];
  //String sPath = _fullpath(fpath, Temp.Str(), MAX_SSI_CHARS);
  //if(sPath == Temp){ 
  //  CWD = Temp;
  //  return STAT_OK;  // It is a fully qualified path passed to the function
  //}

  //return STAT_ERR;

}

String CEnvironment::GetCWD(void)
{
#ifdef LOCAL_ONLY
	char buff[MAX_SSI_CHARS];
	getcwd(buff, MAX_SSI_CHARS);
	String Ret = buff;
	return Ret;
#endif

  return CWD;
}

CStatus CEnvironment::GetAbsolutePath(String& Path, String& Ret)
{
#ifdef LOCAL_ONLY
  Ret = Path;
  return STAT_OK;
#endif

  // THIS NEVER REALLY WORKED...


  if(Path.GetLength() <= 0) return STAT_OK;

  Path.Trim();

  String Drive;
  GetDrive(CWD, Drive);
  //printf("Drive: %s\n", Drive.Str());

  char fpath[MAX_SSI_CHARS];
  if(Path.GetLength() >= MAX_SSI_CHARS){
    //return STAT_ERR;  // Exceeds max path length
    MAKEERR1(ERR03410, MAX_SSI_CHARS);
  }

  // Chech if it is already a recognized path... if so, pass it.
  String sPath = _fullpath(fpath, Path.Str(), MAX_SSI_CHARS);
  if(sPath == Path){ 
    Ret = Path;
    return STAT_OK;  // It is a fully qualified path passed to the function
  }

  // Get rid of any slashes we dont want at end
  StripTrailingSlashes(Path);
  String Tok;
  String Delims = "\\/";
  String Item;
  String Reverse;
  Ret = CWD;

  // Actually, network drives wont be supported...
  if(Path.SubString(0,1) == "\\\\"){
    // Network machine... drive is machine name, and start parse after machine name
    GetDrive(Path, Drive);
    Ret = Drive;      // It is a fully qualified path... consider adding drive letter back (remember UNIX!)
    Path = Path.SubString(Drive.GetLength());
    //return STAT_OK;
  }else if(Path.GetAt(0) == '\\'){  // Set up absolute paths wrt drive
    Ret = Drive + "\\";
    Path = Path.SubString(1);
  }

  // Handles something like c:\\lala\\..
  GetDrive(Path, Drive);
  if(Drive.GetLength() > 0){
    Ret = Drive;      // It is a fully qualified path... consider adding drive letter back (remember UNIX!)
    Path = Path.SubString(Drive.GetLength());
  }
  


  String Temp = Path;

  // Cycle through remainder of path
  Tok = "\\";
  while(Temp.Parse(Delims, Item, &Tok) >= 0){
    if(Item.GetLength() == 0){

    }else if(Item == ".."){
      Ret.Reverse();
      Ret.Parse(Delims, Item);
      Ret.Reverse();
    }else if(Item == "."){
    }else{
      //Ret = Ret + Tok + Item;
      AppendPath(Ret, Item);
    }
  }

  if(Temp == ".."){
      Ret.Reverse();
      Ret.Parse(Delims, Item);
      Ret.Reverse();
  }else if(Temp == "."){
  }else{
    AppendPath(Ret, Temp);
  }

  Ret.Replace("/", "\\");

  //AppendPath(Ret, String(""));


  GetDrive(CWD, Drive);
  if(Ret == Drive){
    Ret = Ret + "\\";
  }

  //struct _finddata_t c_file;
  //long hFile;
  //String Composite = CWD + Path;
  //if( (hFile = _findfirst( Composite, &c_file )) == -1L ){
  //  return STAT_ERR;  // No Such directory / file
  //}
  //Ret = c_file.name;

  return STAT_OK;
}

CStatus CEnvironment::GetDrive(String& Path, String& Drive)
{
  int iPos;
  if(Path.GetLength() < 2){
    //return STAT_ERR;
    MAKEERR0(ERR03411);
  }
  if(Path.SubString(0,1) == String("\\\\")){
    iPos = Path.Find("\\", 2);
    if(iPos >= 0){
      Drive = Path.SubString(0,iPos);
    }else{
      Drive = Path;
    }
  }else if((iPos = Path.Find(":")) > 0){
    iPos = Path.Find("\\", iPos);
    if(iPos > 0){
      Drive = Path.SubString(0,iPos-1);
    }else{
      Drive = Path;
    }
  }else{
    Drive = "";
  }
  
  return STAT_OK;
}

void CEnvironment::AppendPath(String& Path, String& Append)
{
  Path.Trim();
  String Temp = Append;
  StripTrailingSlashes(Temp);

  int len = Path.GetLength();
  if(len <= 0) return;

  char c = Path.GetAt(len-1);
  if(c == '\\' || c == '/'){
    while(Temp.FindOneOf("\\/") == 0){
      Temp = Temp.SubString(1);
      Temp.Trim();
    }
    Path = Path + Temp;
  }else{
    if(Temp.FindOneOf("\\/") == 0){
      Path = Path + Temp;
    }else{
      Path = Path + "\\" + Temp;
    }
  }
}


void CEnvironment::StripTrailingSlashes(String& Input)
{
  Input.Trim();
  Input.Reverse();
  while(Input.FindOneOf("\\/") == 0){
    Input = Input.SubString(1);
    Input.Trim();
  }
  Input.Reverse();
}

CStatus CEnvironment::SetPathFromFile(String& InFile)
{
  if(InFile.GetLength() <= 0) return STAT_OK;

  CStatus Ret;
  String File = InFile;
  String s;
  String Temp;
  Ret = GetAbsolutePath(File, Temp);
  if(!Ret) return Ret;
  File = Temp;
  
  File.Reverse();
  int iPos = File.Parse("\\/", s);
  File.Reverse();

  s.Trim();
  // Don't set directories if file only...
  if(s.GetLength() == 0){
	  return STAT_OK;
  }

  return SetCWD(File);
}

void CEnvironment::IncrementCounts(CStatus& Stat)
{
  if(Stat.GetState() == sERROR){
    ErrCount++;
  }
  if(Stat.GetState() == sWARNING){
    WarnCount++;
  }
}

SSI_INT64 CEnvironment::GetErrCount(void)
{
  return ErrCount;
}

SSI_INT64 CEnvironment::GetWarnCount(void)
{
  return WarnCount;
}

unsigned int CEnvironment::GetStackAddress(void)
{
  return StackAddr;
}

unsigned int CEnvironment::GetStackEnd(void)
{
  //int STACK_SIZE = 500000;  // 1/2 megabyte / 2
  return StackAddr - MAX_STACK_SIZE;
}

void CEnvironment::setInstallDir(String& dir){
	installDir = dir;
}

String CEnvironment::getInstallDir(){
	return installDir;
}



